#include <ecal/ecal.h>

#include <atomic>
#include <chrono>
#include <condition_variable>
#include <iostream>
#include <memory>
#include <mutex>
#include <thread>
#include <vector>

class ClientManager {
 public:
  ClientManager(size_t client_count, size_t service_count, int request_interval_ms)
      : client_count(client_count),
        service_count(service_count),
        request_interval(request_interval_ms),
        running(false) {}

  ~ClientManager() { stop(); }

  void start() {
    running = true;
    create_clients();
    worker_thread = std::thread(&ClientManager::worker_loop, this);
  }

  void stop() {
    running = false;
    if (worker_thread.joinable()) {
      worker_thread.join();
    }
  }

  void print_stats() const {
    std::lock_guard<std::mutex> lock(stats_mutex);
    std::cout << "\n=== Client Statistics ==="
              << "\nTotal clients: " << client_count << "\nServices used: " << service_count
              << "\nRequests sent: " << requests_sent << "\nSuccessful responses: " << responses_success
              << "\nFailed responses: " << responses_failed
              << "\nActive threads: " << (worker_thread.joinable() ? 1 : 0) << "\n========================\n";
  }

 private:
  void create_clients() {
    std::cout << "Creating " << client_count << " service clients for " << service_count << " services...\n";

    clients.reserve(client_count);
    for (size_t i = 0; i < client_count; i++) {
      std::string service_name = "service" + std::to_string((i % service_count) + 1);

      auto client = std::make_unique<eCAL::CServiceClient>(service_name);
      client->AddResponseCallback([this](const auto& response) { this->handle_response(response); });

      clients.emplace_back(std::move(client));
    }
  }

  void handle_response(const eCAL::SServiceResponse& response) {
    std::lock_guard<std::mutex> lock(stats_mutex);

    switch (response.call_state) {
      case call_state_executed:
        responses_success++;
        break;
      case call_state_failed:
        responses_failed++;
        break;
      default:
        break;
    }

    if ((responses_success + responses_failed) % 100 == 0) {
      std::cout << "[" << (responses_success + responses_failed) << "] " << response.method_name << " - "
                << (response.call_state == call_state_executed ? "SUCCESS" : "FAILURE") << std::endl;
    }
  }

  void worker_loop() {
    while (running && eCAL::Ok()) {
      for (auto& client : clients) {
        if (!running) break;

        std::string method_name = "echo";
        std::string request = "Request from client #" + std::to_string(&client - &clients[0]);

        if (client->Call(method_name, request)) {
          std::lock_guard<std::mutex> lock(stats_mutex);
          requests_sent++;
        }

        // 控制请求速率
        std::this_thread::sleep_for(std::chrono::milliseconds(request_interval));
      }

      std::this_thread::sleep_for(std::chrono::milliseconds(10));
    }
  }

  size_t client_count;
  size_t service_count;
  int request_interval;
  std::atomic<bool> running;

  std::vector<std::unique_ptr<eCAL::CServiceClient>> clients;

  // 统计信息
  mutable std::mutex stats_mutex;
  size_t requests_sent = 0;
  size_t responses_success = 0;
  size_t responses_failed = 0;

  // 工作线程
  std::thread worker_thread;
};

int main(int argc, char** argv) {
  size_t client_count = 10;
  size_t service_count = 5;
  int request_interval_ms = 100;

  if (argc > 1) client_count = std::stoul(argv[1]);
  if (argc > 2) service_count = std::stoul(argv[2]);
  if (argc > 3) request_interval_ms = std::atoi(argv[3]);

  if (client_count < 1) client_count = 1;
  if (service_count < 1) service_count = 1;
  if (request_interval_ms < 10) request_interval_ms = 10;

  eCAL::Initialize(argc, argv, "Optimized Massive Client");
  eCAL::Process::SetState(proc_sev_healthy, proc_sev_level1, "Client operational");

  ClientManager manager(client_count, service_count, request_interval_ms);
  manager.start();

  std::cout << "Client manager started. Press Enter to exit...\n";
  std::cin.ignore();

  manager.stop();
  manager.print_stats();

  eCAL::Finalize();
  return 0;
}